package com.example.gatewayserver.filter;

import com.example.gatewayserver.feign.Oauth2ServerFeign;
import com.example.gatewayserver.properties.NoAuthorizationProperties;
import com.example.gatewayserver.util.JwtUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.security.PublicKey;
import java.util.Map;

@Slf4j
@EnableConfigurationProperties(NoAuthorizationProperties.class)
@Component
public class AuthFilter implements GlobalFilter, InitializingBean {

    /**
     * 请求各个微服务 不需要用户认证的URL
     */
    @Autowired
    private NoAuthorizationProperties notAuthUrlProperties;

    private PublicKey publicKey;


    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private Oauth2ServerFeign oauth2ServerFeign;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

        String currentUrl = request.getURI().getPath();

        //过滤不需要认证的url
        if(shouldSkip(currentUrl)) {
            log.info("跳过认证的URL:{}",currentUrl);
            return chain.filter(exchange);
        }
        log.info("需要认证的URL:{}",currentUrl);

        String jwt = request.getHeaders().getFirst("Authorization");
        // 当没有token是不校验，直接跳转
        if (StringUtils.isEmpty(jwt)) {
            return chain.filter(exchange);
        }

        // 根据公钥和jwt获取用户信息
        Claims claims = JwtUtils.validateJwtToken(jwt, publicKey);
        // 包装信息到下一个路径
        return chain.filter(wrapHeader(exchange,claims));
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //获取公钥  TODO
        this.publicKey = JwtUtils.genPulicKey(restTemplate);

        /*// 获取的jwt的加密方式及密码
        Map<String,String> map = oauth2ServerFeign.tokenKey();
        log.info("jwt信息: {}",map);

        String value = map.get("value");

        // 包装公钥
        PublicKey publicKey = JwtUtils.genPulicKey(value);*/

    }


    /**
     * 方法实现说明:不需要授权的路径
     * @author:smlz
     * @param currentUrl 当前请求路径
     * @return:
     * @exception:
     * @date:2019/12/26 13:49
     */
    private boolean shouldSkip(String currentUrl) {
        //路径匹配器(简介SpringMvc拦截器的匹配器)
        //比如/oauth/** 可以匹配/oauth/token    /oauth/check_token等
        PathMatcher pathMatcher = new AntPathMatcher();
        for(String skipPath:notAuthUrlProperties.getNoAuthorizationSet()) {
            if(pathMatcher.match(skipPath,currentUrl)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 请求头中的 token的开始
     */
    private static final String AUTH_HEADER = "bearer ";

    public static Claims validateJwtToken(String authHeader, PublicKey publicKey) {
        String token =null ;
        try{
            token = StringUtils.substringAfter(authHeader, AUTH_HEADER);

            Jwt<JwsHeader, Claims> parseClaimsJwt = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);

            Claims claims = parseClaimsJwt.getBody();

            //log.info("claims:{}",claims);

            return claims;

        }catch(Exception e){

            log.error("校验token异常:{},异常信息:{}",token,e.getMessage());

            throw new RuntimeException("token失效!");
        }
    }

    private ServerWebExchange wrapHeader(ServerWebExchange serverWebExchange, Claims claims) {
        ObjectMapper mapper = new ObjectMapper();
        String userInfo = null;
        try {
            userInfo = mapper.writeValueAsString(claims);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
//        String loginUserInfo = JSON.toJSONString(claims);

        log.info("jwt的用户信息:{}",userInfo);

        String userId = claims.get("additionalInfo", Map.class).get("userId").toString();

        String phone = claims.get("additionalInfo",Map.class).get("phone").toString();

        //向headers中放文件，记得build
        ServerHttpRequest request = serverWebExchange.getRequest().mutate()
                .header("username",claims.get("user_name",String.class))
                .header("userId",userId)
                .header("phone",phone)
                .build();

        //将现在的request 变成 change对象
        return serverWebExchange.mutate().request(request).build();
    }

}
